package com.kc.gb.device.plugins.ptl.service.impl;

import com.kc.gb.device.common.properties.DeviceProperties;
import com.kc.gb.device.common.utils.SpringHelper;
import com.kc.gb.device.plugins.ptl.events.support.PtlCommandEvent;
import com.kc.gb.device.plugins.ptl.service.support.ableat.ABLEATPtlService;
import com.kc.gb.device.plugins.ptl.service.PtlHardwareService;
import com.kc.gb.device.plugins.ptl.dto.PtlLightState;
import com.kc.gb.device.plugins.ptl.dto.PtlTurnOffEvent;
import com.kc.gb.feign.ptl.support.dtos.*;
import com.kc.gb.feign.ptl.support.enums.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
@Service
public class PtlHardwareServiceImpl implements PtlHardwareService {

    @Resource
    DeviceProperties deviceProperties;

    private Map<Integer,PtlLightState> SIMULATE_STATE_STORE = new ConcurrentHashMap<>();
    private Map<Integer,PtlLightState> DEBUGGER_STATE_STORE = new ConcurrentHashMap<>();

    @Override
    public <T extends AbstractPtlCommand> void consumeCommands(List<T> commands, boolean debugMode) {
        if(CollectionUtils.isEmpty(commands)){
            return;
        }
        Throwable lastException = null;
        for (T command : commands) {
            try {
                // PTL command event 通知前端界面刷新
                PtlCommandType type = command.getCommandType();
                if(PtlCommandType.LIGHT.equals(type)){
                    LightCommand cmd = (LightCommand) command;
                    int lightNo = cmd.getLightNo();
                    PtlLightOnOff status = cmd.getLightStatus();
                    PtlLightColor color = cmd.getLightColor();
                    int interval = cmd.getInterval();
                    if(ObjectUtils.isEmpty(color)){
                        color = PtlLightColor.RED;
                    }
                    // 调用私有方法，保存模拟器状态
                    light(debugMode,lightNo,status, PtlLightColor.RED,(short)interval);
                }
                if(PtlCommandType.LED.equals(type)){
                    LedCommand cmd = (LedCommand) command;
                    int lightNo = cmd.getLightNo();
                    int num = cmd.getNum();
                    PtlLedOnOff ledStatus = cmd.getLedStatus();
                    // 调用私有方法，保存模拟器状态
                    lednum(debugMode,lightNo,num,ledStatus);
                }
                if(PtlCommandType.BUTTON.equals(type)){
                    ButtonCommand cmd = (ButtonCommand) command;
                    int lightNo = cmd.getLightNo();
                    PtlButtonStatus buttonStatus = cmd.getButtonStatus();
                    // 调用私有方法，保存模拟器状态
                    button(debugMode,lightNo,buttonStatus);

                }
                if(PtlCommandType.BEEP.equals(type)){
                    BeepCommand cmd = (BeepCommand) command;
                    int lightNo = cmd.getLightNo();
                    PtlBeepStatus buttonStatus = cmd.getBeepStatus();
                    // 调用私有方法，保存模拟器状态
                    beep(debugMode,lightNo,buttonStatus);
                }
            } catch (Throwable e) {
                // 硬件连接异常时，保证模拟器所有指令执行完毕
                log.error("Command:{} error:{}",command,e.getMessage(),e);
                lastException = e;
            }
        }
        // 发布PTL灯光执行事件
        SpringHelper.getApplicationContext().publishEvent(new PtlCommandEvent<>(commands));
        // 抛出异常信息
        if(ObjectUtils.isNotEmpty(lastException)){
            throw new RuntimeException(lastException);
        }
    }

    @Override
    public void confirmed(int lightNo) {
        SpringHelper.getApplicationContext().publishEvent(new PtlTurnOffEvent(lightNo));
    }

    @Override
    public Map<Integer, PtlLightState> getStateStore(boolean inDebugMode) {
        if(inDebugMode){
            return DEBUGGER_STATE_STORE;
        }
        return SIMULATE_STATE_STORE;
    }

    @Override
    public List<PtlLightState> getLightStates(boolean inDebugMode, List<Integer> lightNos) {
        Map<Integer,PtlLightState> stateStore = getStateStore(inDebugMode);
        if(inDebugMode){
            stateStore = DEBUGGER_STATE_STORE;
        }else{
            stateStore = SIMULATE_STATE_STORE;
        }
        if(CollectionUtils.isEmpty(lightNos)){
            return new ArrayList<>();
        }
        List<PtlLightState> states = new ArrayList<>();
        for (Integer lightNo : lightNos) {
            PtlLightState exist = stateStore.get(lightNo);
            if(ObjectUtils.isEmpty(exist)){
                PtlLightState defaultState = new PtlLightState(lightNo);
                stateStore.put(lightNo,defaultState);
            }
            states.add(stateStore.get(lightNo));
        }
        return states;
    }

    private ABLEATPtlService getAbleLightDevice(){
        return SpringHelper.getBean(deviceProperties.getDevicePtlImpl(), ABLEATPtlService.class);
    }

    void light(boolean debugMode, int lightNo, PtlLightOnOff lightStatus, PtlLightColor color, short interval){
        AtomicBoolean DEBUG_MODE = new AtomicBoolean(debugMode);
        PtlLightState light = getStateStore(DEBUG_MODE.get()).get(Integer.valueOf(lightNo));
        if(light == null){
            light = new PtlLightState(lightNo);
            getStateStore(DEBUG_MODE.get()).put(Integer.valueOf(lightNo),light);
        }
        light.setLightStatus(lightStatus);
        light.setColor(color);
        // 执行硬件指令
        ABLEATPtlService ptlService = getAbleLightDevice();
        ptlService.light(lightNo,lightStatus, color,(short)interval);
    }

    void lednum(boolean debugMode,int lightNo, int num, PtlLedOnOff ledStatus){
        AtomicBoolean DEBUG_MODE = new AtomicBoolean(debugMode);
        PtlLightState light = getStateStore(DEBUG_MODE.get()).get(Integer.valueOf(lightNo));
        if(light == null){
            light = new PtlLightState(lightNo);
            getStateStore(DEBUG_MODE.get()).put(Integer.valueOf(lightNo),light);
        }
        light.setLedStatus(ledStatus);
        light.setNum(num);
        // 执行硬件指令
        ABLEATPtlService ptlService = getAbleLightDevice();
        ptlService.lednum(lightNo,num,ledStatus);
    }

    void button(boolean debugMode,int lightNo, PtlButtonStatus buttonStatus){
        AtomicBoolean DEBUG_MODE = new AtomicBoolean(debugMode);
        PtlLightState light = getStateStore(DEBUG_MODE.get()).get(Integer.valueOf(lightNo));
        if(light == null){
            light = new PtlLightState(lightNo);
            getStateStore(DEBUG_MODE.get()).put(Integer.valueOf(lightNo),light);
        }
        light.setButtonStatus(buttonStatus);
        // 执行硬件指令
        ABLEATPtlService ptlService = getAbleLightDevice();
        ptlService.button(lightNo,buttonStatus);
    }

    void beep(boolean debugMode,int lightNo, PtlBeepStatus beepStatus){
        AtomicBoolean DEBUG_MODE = new AtomicBoolean(debugMode);
        PtlLightState light = getStateStore(DEBUG_MODE.get()).get(Integer.valueOf(lightNo));
        if(light == null){
            light = new PtlLightState(lightNo);
            getStateStore(DEBUG_MODE.get()).put(Integer.valueOf(lightNo),light);
        }
        light.setBeepStatus(beepStatus);
        // 执行硬件指令
        ABLEATPtlService ptlService = getAbleLightDevice();
        ptlService.beep(lightNo,beepStatus);
    }
}
